<template>
  <div class="voice-recorder">
    <!-- 自定义按钮样式或使用默认样式 -->
    <slot name="button" 
          :is-recording="isRecording" 
          :start-recording="startRecording" 
          :stop-recording="stopRecording">
      <button 
        class="record-button" 
        :class="[buttonClass, { 'recording': isRecording }]"
        @mousedown="startRecording" 
        @mouseup="stopRecording"
        @mouseleave="stopRecording"
        :style="buttonStyle"
      >
        {{ isRecording ? recordingText : defaultText }}
      </button>
    </slot>
    
    <!-- 可选的状态显示 -->
    <slot name="status" :is-recording="isRecording" :is-processing="isProcessing">
      <div v-if="showStatus" class="status">
        <span v-if="isRecording" class="recording-status">{{ recordingText }}</span>
        <span v-else-if="isProcessing" class="processing-status">{{ processingText }}</span>
        <span v-else>{{ defaultText }}</span>
      </div>
    </slot>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';

// 定义组件接收的属性
const props = defineProps({
  // 按钮文本配置
  defaultText: {
    type: String,
    default: '按住说话'
  },
  recordingText: {
    type: String,
    default: '正在录音...'
  },
  processingText: {
    type: String,
    default: '正在处理...'
  },
  
  // 样式配置
  buttonClass: {
    type: [String, Object, Array],
    default: ''
  },
  buttonStyle: {
    type: Object,
    default: () => ({})
  },
  showStatus: {
    type: Boolean,
    default: false
  },
  
  // 录音配置
  mimeType: {
    type: String,
    default: 'audio/mp3' // 或 'audio/wav'，取决于浏览器支持
  },
  audioBitsPerSecond: {
    type: Number,
    default: 128000
  }
});

// 定义事件
const emit = defineEmits([
  'recording-start',     // 开始录音
  'recording-end',       // 结束录音
  'audio-available',     // 音频数据可用
  'error'                // 错误事件
]);

// 内部状态
const isRecording = ref(false);
const isProcessing = ref(false);
const mediaRecorder = ref(null);
const audioChunks = ref([]);
const stream = ref(null);

// 初始化录音功能
const initRecorder = async () => {
  try {
    // 确保之前的资源已经清理
    cleanup();
    
    // 请求麦克风访问权限
    const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
    stream.value = mediaStream;
    
    // 创建MediaRecorder实例
    const options = {
      audioBitsPerSecond: props.audioBitsPerSecond
    };
    
    // 检查MIME类型是否受支持
    if (MediaRecorder.isTypeSupported(props.mimeType)) {
      options.mimeType = props.mimeType;
    }
    
    mediaRecorder.value = new MediaRecorder(mediaStream, options);
    
    // 收集录音数据
    mediaRecorder.value.addEventListener('dataavailable', (event) => {
      if (event.data.size > 0) {
        audioChunks.value.push(event.data);
      }
    });
    
    // 录音停止后的处理
    mediaRecorder.value.addEventListener('stop', () => {
      // 只有在有数据的情况下处理
      if (audioChunks.value.length > 0) {
        processAudioData();
      }
    });
    
    return true;
  } catch (error) {
    console.error('麦克风访问失败:', error);
    emit('error', { 
      type: 'mic-access',
      message: '无法访问麦克风，请确保已授予麦克风访问权限',
      error 
    });
    return false;
  }
};

// 开始录音 - 每次按下按钮时重新初始化
const startRecording = async () => {
  // 每次都重新初始化录音设备
  if (!(await initRecorder())) {
    return;
  }
  
  // 清空之前的录音数据
  audioChunks.value = [];
  
  // 开始录音
  isRecording.value = true;
  try {
    // 每100毫秒收集一次数据
    mediaRecorder.value.start(100);
    emit('recording-start');
  } catch (error) {
    console.error('开始录音失败:', error);
    isRecording.value = false;
    emit('error', { 
      type: 'recording-start',
      message: '开始录音失败',
      error 
    });
    
    // 初始化失败时清理资源
    cleanup();
  }
};

// 停止录音并释放麦克风
const stopRecording = () => {
  if (!isRecording.value) return;
  
  isRecording.value = false;
  
  try {
    // 停止录音
    if (mediaRecorder.value && mediaRecorder.value.state !== 'inactive') {
      mediaRecorder.value.stop();
      emit('recording-end');
    }
  } catch (error) {
    console.error('停止录音失败:', error);
  } finally {
    // 无论成功与否，都释放麦克风资源
    // 这里不立即调用cleanup，让processAudioData有机会处理数据
    // 数据处理完成后会自动释放资源
  }
};

// 处理录音数据
const processAudioData = async () => {
  if (audioChunks.value.length === 0) {
    cleanup(); // 如果没有数据，直接清理资源
    return;
  }
  
  isProcessing.value = true;
  
  try {
    // 创建音频Blob
    const audioBlob = new Blob(audioChunks.value, { type: props.mimeType });
    
    // 创建音频URL (可选，用于预览)
    const audioUrl = URL.createObjectURL(audioBlob);
    
    // 发送音频数据到父组件
    emit('audio-available', {
      blob: audioBlob,
      url: audioUrl,
      type: props.mimeType
    });
  } catch (error) {
    console.error('处理音频数据失败:', error);
    emit('error', { 
      type: 'processing',
      message: '处理音频数据失败',
      error 
    });
  } finally {
    isProcessing.value = false;
    
    // 数据处理完成后，释放麦克风资源
    cleanup();
  }
};

// 资源清理
const cleanup = () => {
  // 停止录音
  if (mediaRecorder.value && mediaRecorder.value.state !== 'inactive') {
    try {
      mediaRecorder.value.stop();
    } catch (e) {
      console.error('停止MediaRecorder失败:', e);
    }
  }
  
  // 释放麦克风资源
  if (stream.value) {
    try {
      stream.value.getTracks().forEach((track) => {
        track.stop();
        stream.value.removeTrack(track);
      });
    } catch (e) {
      console.error('释放音频轨道失败:', e);
    }
    stream.value = null;
  }
  
  // 清空对象引用
  mediaRecorder.value = null;
};

// 暴露组件方法给父组件
defineExpose({
  startRecording,
  stopRecording
});

onMounted(() => {
  // 组件挂载时不初始化，等待用户按下按钮时初始化
});

onUnmounted(() => {
  // 组件卸载前确保资源被释放
  cleanup();
});
</script>

<style scoped>
.voice-recorder {
  display: inline-block;
}

.record-button {
  padding: 1rem 2rem;
  font-size: 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s;
  user-select: none;
}

.record-button.recording {
  background-color: #f44336;
  animation: pulse 1.5s infinite;
}

.status {
  margin-top: 0.5rem;
  font-size: 14px;
  color: #666;
}

.recording-status {
  color: #f44336;
  font-weight: bold;
}

.processing-status {
  color: #ff9800;
  font-weight: bold;
}

@keyframes pulse {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
  100% {
    transform: scale(1);
  }
}
</style>

